#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <assert.h>
#include <stdlib.h>

#include "list.h"

int main(int argc, char ** argv)
{
  void * list;
  void * list2;
  list_t iter;
  int i;
  char * buf;
  char * buf2;
  char * buf3;

  void * ptr;
  void * ptr2;
  void * ptr3;
  
  /*
  printf("INITIAL MEMORY STATS:\n");
  malloc_stats();
  */

  list = list_alloc();

  if ((0 != list_count(list)) || (!list_is_empty(list)))
    return 1;

  /* add five elements to the list */
  for (i=0; i<5; i++)
  {
    buf = (char *)malloc(20);
    sprintf(buf, "%d", i);
    list_insert_front(list, buf);
  }

  if (5 != list_count(list))
    return 2;

  /* scan the list in reverse */
  i = 0;
  for(iter = list_prev(list); iter; iter = list_prev(iter))
  {
    if (atoi((char *) list_item(iter)) != i)
      return 20;
    i++;
  }

  /* now delete all the elements from the list and print them */
  i = 4;
  while((buf = list_delete_front(list)))
  {
    if (atoi(buf) != i)
      return 3;
    i --;
    
    free(buf);
  }

  if ((0 != list_count(list)) || (!list_is_empty(list)))
    return 4;
  
  /* free the list */
  list_free(list);
  
  /* allocate two lists */
  list = list_alloc();
  list2 = list_alloc();

  /* add some elements to the first list */
  for (i=0; i<5; i++)
  {
    buf = (char *)malloc(20);
    sprintf(buf, "%d", i);
    list_insert_end(list, buf);
  }
  /* and some more to the second */
  for (i=9; i>4; i--)
  {
    buf = (char *)malloc(20);
    sprintf(buf, "%d", i);
    list_insert_front(list2, buf);
  }

  /* extend the first list and free the second */
  list_join(list, list2);

  /* delete and print from the second list */
  i = 0;
  while((buf = list_delete_front(list)))
  {
    if (atoi(buf) != i)
      return 5;
    i ++;
    
    free(buf);
  }
  
  if ((0 != list_count(list)) || (!list_is_empty(list)))
    return 6;

  buf = (char *)malloc(sizeof(char));
  *buf = 'a';

  list_insert_end(list, buf);
  buf = NULL;
  
  list_item1(list, (void **)&buf);
  
  if (*buf != 'a')
    return 7;

  buf = (char *)malloc(sizeof(char));
  *buf = 'b';

  list_insert_end(list, buf);
  buf = NULL;

  list_item2(list, (void **)&buf, (void **)&buf2);
  
  if ((*buf != 'a') || (*buf2 != 'b'))
    return 8;
  
  buf = (char *)malloc(sizeof(char));
  *buf = 'c';

  list_insert_end(list, buf);
  buf = NULL;

  list_item3(list, (void **)&buf, (void **)&buf2, (void **)&buf3);
  
  if ((*buf != 'a') || (*buf2 != 'b') || (*buf3 != 'c'))
    return 9;

  /* Now test list_delete_elem */
  iter = list_next(list); 
  iter = list_next(iter);
  buf = list_item(iter);
  if (*buf != 'b')
    return 10;
  list_delete_elem(iter);
  free(buf);

  list_item2(list, (void **)&buf, (void **)&buf2);
  
  if ((*buf != 'a') || (*buf2 != 'c') || (list_count(list) != 2))
    return 11;

  buf = list_item(list_prev(list));
  if (*buf != 'c')
    return 12;

  buf2 = list_delete_end(list);

  list_item1(list, (void **)&buf);
  
  if ((*buf != 'a') || (*buf2 != 'c') || (list_count(list) != 1))
    return 13;

  while((buf = list_delete_front(list)))
  {
    free(buf);
  }
  list_free(list);

  /* test list_remove */
  buf = (char *)malloc(sizeof(char));
  *buf = 'a';

  buf2 = (char *)malloc(sizeof(char));
  *buf2 = 'b';

  buf3 = (char *)malloc(sizeof(char));
  *buf3 = 'c';

  list = list_alloc3(buf, buf2, buf3);

  if (!list_find(list, buf) || !list_find(list, buf2) || !list_find(list, buf3)
      || list_find(list, NULL))
    return 21;
  
  list_remove(list, buf2);
  free(buf2);

  list_remove(list, buf3);
  free(buf3);
  
  list_remove(list, buf);
  free(buf);
  
  if (!list_is_empty(list))
    return 14;
  
  free(list);

  list = list_alloc1(NULL);
  list2 = list_alloc1(NULL);

  list_join(list, list2);
  
  if (list_count(list) != 2)
    return 15;
  
  free(list);

  buf = (char *)malloc(sizeof(char));
  buf2 = (char *)malloc(sizeof(char));
  buf3 = (char *)malloc(sizeof(char));
  
  *buf = 'a';
  *buf2 = 'b';
  *buf3 = 'c';
  
  list = list_alloc3(buf, buf2, buf3);

  if ((list_index(list, 0) != buf) || (list_index(list, 1) != buf2)
      || (list_index(list, 2) != buf3))
    return 22;
  
  ptr = list_remove_random(list);
  if (list_count(list) != 2)
    return 16;
  
  if ((ptr != buf) && (ptr != buf2) && (ptr != buf3))
    return 17;
  
  ptr2 = list_remove_random(list);
  if (list_count(list) != 1)
    return 18;
  
  if (((ptr2 != buf) && (ptr2 != buf2) && (ptr2 != buf3)) || (ptr2 == ptr))
    return 19;

  ptr3 = list_remove_random(list);
  if (!list_is_empty(list))
    return 20;
  
  if (((ptr3 != buf) && (ptr3 != buf2) && (ptr3 != buf3)) || (ptr3 == ptr)
      || (ptr3 == ptr2))
    return 21;

  
  /*
  printf("FINAL MEMORY STATS:\n");
  malloc_stats();
  */
  return 0;
}
